package mn.more.wits.client;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.*;
import mn.more.wits.client.dto.ExamQuestionAttachmentDTO;
import mn.more.wits.client.dto.ExamQuestionDTO;
import mn.more.wits.client.dto.ExamSessionDTO;
import mn.more.wits.client.util.FormatUtil;
import net.mygwt.ui.client.Events;
import net.mygwt.ui.client.Registry;
import net.mygwt.ui.client.Style;
import net.mygwt.ui.client.event.BaseEvent;
import net.mygwt.ui.client.event.Listener;
import net.mygwt.ui.client.event.SelectionListener;
import net.mygwt.ui.client.widget.ContentPanel;
import net.mygwt.ui.client.widget.Info;
import net.mygwt.ui.client.widget.List;
import net.mygwt.ui.client.widget.ListItem;
import net.mygwt.ui.client.widget.MessageBox;
import net.mygwt.ui.client.widget.ToolBar;
import net.mygwt.ui.client.widget.ToolItem;
import net.mygwt.ui.client.widget.layout.BorderLayout;
import net.mygwt.ui.client.widget.layout.BorderLayoutData;

/**
 * @author <a href="mailto:mike.liu@aptechmongolia.edu.mn">Mike Liu</a>
 * @version $Revision: 119 $
 */
public class ExamPanel extends ContentPanel {

	public static final String ID = "exam-panel";
	private static final AppMsg APP_MSG = AppMsg.Self.get();

	private ContentPanel questionPanel = new ContentPanel(Style.HEADER);
	private ResponsePanel responsePanel = new ResponsePanel();
	private ExamPanel.ExamClock clock = new ExamClock();
	private ExamSessionDTO session;
	private int currentQuesIndex;

	private class CountDownTimer extends Timer {

		private HTML label;
		private int start;
		private int remaining;

		private CountDownTimer(HTML label) {
			this.label = label;
		}

		public void setMax(int max) {
			this.start = max;
			this.remaining = max;
			label.setStyleName("exam-clock-time");
		}

		public void run() {
			if (start < 1) {
				label.setText(APP_MSG.examClockNone());
				cancel();
			} else {
				remaining--;
				if (remaining < 1) {
					notifyTimesup(label);
					cancel();
				}
				label.setText(FormatUtil.formatTime(remaining));
			}
		}
	}

	private class ExamClock extends HorizontalPanel {

		public static final String ID = "exam-clock";

		private HTML lblTitle = new HTML(APP_MSG.examClockTitle(), false);
		private HTML lblExam = new HTML(APP_MSG.examClockExam(), false);
		private HTML lblExamTime = new HTML(APP_MSG.examClockNone(), false);
		private HTML lblSpacer = new HTML(APP_MSG.examClockSpacer(), false);
		private HTML lblQuestion = new HTML(APP_MSG.examClockQuestion(), false);
		private HTML lblQuesTime = new HTML(APP_MSG.examClockNone(), false);

		private CountDownTimer examTimer = new CountDownTimer(lblExamTime);
		private CountDownTimer quesTimer = new CountDownTimer(lblQuesTime);

		public ExamClock() {

			lblTitle.setStyleName("exam-clock-lbl");
			lblExam.setStyleName("exam-clock-lbl");
			//lblExamTime = new HTML(FormatUtil.formatTime(examSeconds), false);
			lblExamTime.setStyleName("exam-clock-time");
			lblQuestion.setStyleName("exam-clock-lbl");
			//lblQuesTime = new HTML(FormatUtil.formatTime(quesSeconds), false);
			lblQuesTime.setStyleName("exam-clock-time");

			setStyleName("exam-clock");
			add(lblTitle);
			add(lblExam);
			add(lblExamTime);
			add(lblSpacer);
			add(lblQuestion);
			add(lblQuesTime);

			Registry.register(ID, this);
		}

		void setExamCountdown(int maxExamSeconds) {
			if (maxExamSeconds > 0) {
				examTimer.cancel();
				examTimer.setMax(maxExamSeconds);
				examTimer.scheduleRepeating(1000);
			}
		}

		void setQuesCountDown(int maxQuesSeconds) {
			if (maxQuesSeconds > 0) {
				quesTimer.cancel();
				quesTimer.setMax(maxQuesSeconds);
				quesTimer.scheduleRepeating(1000);
			}
		}
	}

	private class ResponsePanel extends ContentPanel {

		public static final String ID = "exam-response";
		private List selection = new List(Style.MULTI | Style.FLAT | Style.CHECK);
		private CommandToolBar commands = new CommandToolBar();

		public ResponsePanel() {
			super(Style.HEADER);
			setId(ID);
			setPadding(0);

			BorderLayout layout = new BorderLayout();
			layout.setSpacing(0);
			layout.setMargin(0);
			setLayout(layout);

			selection.setScrollEnabled(true);
			selection.setBorders(false);
			selection.addListener(Events.SelectionChange, new Listener() {

				public void handleEvent(BaseEvent be) {
					List list = (List) be.widget;
					ListItem selected = list.getSelectedItem();
					selected.setChecked(!selected.isChecked());
				}
			});

			add(selection, new BorderLayoutData(Style.CENTER));
			add(commands, new BorderLayoutData(Style.SOUTH, 25, 25, 25));

			Registry.register(ID, this);
		}
	}

	private class CommandToolBar extends ToolBar {

		public static final String ID = "exam-command";

		private ToolItem finish = new ToolItem(Style.PUSH);
		private ToolItem forfeit = new ToolItem(Style.PUSH);
		private ToolItem first = new ToolItem(Style.PUSH);
		private ToolItem next = new ToolItem(Style.PUSH);
		private ToolItem refresh = new ToolItem(Style.PUSH);
		private ToolItem previous = new ToolItem(Style.PUSH);
		private ToolItem last = new ToolItem(Style.PUSH);

		public CommandToolBar() {
			setId(ID);
			setFrame(false);
			setPadding(0);
			setBorders(true);
			setStyleName("exam-command");

			finish.setText(APP_MSG.examCommandFinish());
			finish.setIconStyle("exam-command-finish-icon");
			finish.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					Info.show("Exam Command", "'Finish' selected", "");
				}
			});

			forfeit.setText(APP_MSG.examCommandForfeit());
			forfeit.setIconStyle("exam-command-forfeit-icon");
			forfeit.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					Info.show("Exam Command", "'Forfeit' selected", "");
				}
			});

			refresh.setText(APP_MSG.examCommandRefresh());
			refresh.setIconStyle("exam-command-refresh-icon");
			refresh.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					Info.show("Exam Command", "'Refresh' selected", "");
				}
			});

			first.setText(APP_MSG.examCommandFirst());
			first.setIconStyle("exam-command-first-icon-disabled");
			first.disable();
			first.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					currentQuesIndex = 0;
					showExam(DummyBootstrap.getSampleQuestion(currentQuesIndex));
				}
			});

			next.setText(APP_MSG.examCommandNext());
			next.setIconStyle("exam-command-next-icon-disabled");
			next.disable();
			next.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					showExam(DummyBootstrap.getSampleQuestion(++currentQuesIndex));
				}
			});

			previous.setText(APP_MSG.examCommandPrevious());
			previous.setIconStyle("exam-command-previous-icon-disabled");
			previous.disable();
			previous.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					showExam(DummyBootstrap.getSampleQuestion(--currentQuesIndex));
				}
			});

			last.setText(APP_MSG.examCommandLast());
			last.setIconStyle("exam-command-last-icon-disabled");
			last.disable();
			last.addSelectionListener(new SelectionListener() {

				public void widgetSelected(BaseEvent be) {
					currentQuesIndex = session.getTotalQuestions() - 1;
					showExam(DummyBootstrap.getSampleQuestion(currentQuesIndex));
				}
			});

			add(new ToolItem(Style.SEPARATOR));
			add(finish);
			add(new ToolItem(Style.SEPARATOR));
			add(forfeit);
			add(new ToolItem(Style.SEPARATOR));
			add(refresh);
			add(new ToolItem(Style.SEPARATOR));
			add(new ToolItem(Style.FILL));
			add(new ToolItem(Style.SEPARATOR));
			add(first);
			add(new ToolItem(Style.SEPARATOR));
			add(previous);
			add(new ToolItem(Style.SEPARATOR));
			add(next);
			add(new ToolItem(Style.SEPARATOR));
			add(last);
			add(new ToolItem(Style.SEPARATOR));

			Registry.register(ID, this);
		}

		public void enableFirst(boolean enable) {
			if (enable) { first.enable(); } else { first.disable(); }
		}

		public void enablePrevious(boolean enable) {
			if (enable) { next.enable(); } else { next.disable(); }
		}

		public void enableRefresh(boolean enable) {
			if (enable) { refresh.enable(); } else { refresh.disable(); }
		}

		public void enableNext(boolean enable) {
			if (enable) { next.enable(); } else { next.disable(); }
		}

		public void enableLast(boolean enable) {
			if (enable) { last.enable(); } else { last.disable(); }
		}
	}

	public ExamPanel() {
		setStyle(Style.HEADER);
		setId(ID);

		BorderLayout layout = new BorderLayout();
		layout.setSpacing(0);
		layout.setMargin(5);
		setLayout(layout);

		getHeader().addWidget(clock);

		questionPanel.setPadding(5);
		questionPanel.setScrollEnabled(true);

		add(questionPanel, new BorderLayoutData(Style.CENTER));
		add(responsePanel, new BorderLayoutData(Style.SOUTH, 150, 100, 300));

		Registry.register(ID, this);

		// todo - BEGIN testing only, gotta remove
		initPanel(DummyBootstrap.getSampleData());
		showExam(DummyBootstrap.getSampleQuestion(0));
		// todo - END testing only, gotta remove

		AppContext.setStatusMessage(APP_MSG.examImg(),
		                            APP_MSG.examStatusStarted(session.getTestName(), session.getSubjectName()));
	}

	public void initPanel(ExamSessionDTO session) {
		this.session = session;
		getHeader().setText(session.getSubjectName() + " - " + session.getTestName());
		clock.setExamCountdown(session.getMaxMinutes());
	}

	public void showExam(ExamQuestionDTO exam) {
		AppContext.showLoading();

		questionPanel.removeAll();
		questionPanel.setText(APP_MSG.examQuestionTitle(exam.getIndex(), session.getTotalQuestions()));
		questionPanel.add(new HTML(exam.getText()));
		if (exam.getAttachments() != null) {
			for (int i = 0; i < exam.getAttachments().length; i++) {
				// todo: need to consider display order
				ExamQuestionAttachmentDTO attachment = exam.getAttachments()[i];
				ContentPanel attachmentPanel = new ContentPanel(Style.HEADER | Style.COLLAPSE);
				attachmentPanel.setStyleName("exam-ques-attachment");
				attachmentPanel.setText(attachment.getDisplayName());
				attachmentPanel.add(new HTML(APP_MSG.examQuestionCode(attachment.getText())));
				questionPanel.add(attachmentPanel);
			}
		}
		questionPanel.layout(true);

		if (exam.getType() == ExamQuestionDTO.TYPE_MCQ) {
			responsePanel.setText(APP_MSG.examMcqTitle(exam.getMcqMaxSelect()));
			responsePanel.getHeader().setTitle(APP_MSG.examMcqHint(exam.getMcqMaxSelect()));
		}
		// todo: figure out the else part

		responsePanel.selection.removeAll();
		for (int i = 0; i < exam.getResponses().length; i++) {
			String text = exam.getResponses()[i];
			ListItem item = new ListItem(text);
			item.setData(i + "");
			item.setChecked(false);
			responsePanel.selection.add(item);
		}

		ExamPanel.CommandToolBar commands = responsePanel.commands;
		commands.enableFirst(!exam.isFirst() && session.isBackwardAllowed());
		commands.enablePrevious(!exam.isFirst() && session.isBackwardAllowed());
		commands.enableNext(!exam.isLast() && session.isForwardWithoutAnswer());
		commands.enableLast(!exam.isLast() && session.isForwardWithoutAnswer());
		if (exam.isLast() && commands.last.isEnabled()) { commands.enableLast(false); }
		if (exam.isFirst() && commands.first.isEnabled()) { commands.enableFirst(false); }

		clock.setQuesCountDown(exam.getMaxMinute());

		AppContext.hideLoading();
	}

	private void notifyTimesup(HTML label) {
		label.setStyleName("exam-clock-timesup");

		String msg = null;
		if (label == clock.lblExamTime) {
			// exam time's up
			msg = APP_MSG.examClockExamTimesup();
		}
		if (label == clock.lblQuesTime) {
			// question time's up
			msg = APP_MSG.examClockQuesTimesup();
		}

		MessageBox mb = new MessageBox(Style.ICON_ERROR, Style.DEFAULT);
		mb.setText(msg);
		mb.show();

		// todo: need to nullify exam|question
	}

}
